package com.cccyy.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class HttpUtil {
    private static final String USER_AGENT = "user-agent";
    private static final String USER_AGENT_VALUE = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)";
    private static final String CONNECTION = "connection";
    private static final String CONNECTION_VALUE = "Keep-Alive";
    private static final String ACCEPT = "accept";
    private static final String UTF8 = "utf-8";
    private static final String ACCEPT_CHARSET = "accept-charset";
    private static final String CONTENTTYPE = "contentType";
    private static final String SSL = "ssl";
    private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);

    protected HttpUtil() {

    }

    //这里讲述下发送请求常见
    //### 常见发送请求的数据格式
    //1. **application/x-www-form-urlencoded**： form表单默认的数据格式，提交的数据按照 `key1=val1&key2=val2` 的方式进行编码，key 和 val 都进行了 URL 转码。
    //2. **multipart/form-data**：  此类型一般用来发送文件/图片。在需要进行文件上传时，就需要使用该格式。
    //3. **application/json**： 这个类型一般用来发送JSON类型的数据。
    //4. **text/xml**： 发送的data是XML格式。
    //
    //### 常见网络协议
    //1. **HTTP协议**：
    // GET    | 获取资源
    // POST   | 新增或者更新
    // PUT    | 更新资源
    // DELETE | 删除资源
    //2. **TCP/IP协议**：
    //4. **其他协议**：
    //    * FTP（文件传输协议）：用于在网络上传输文件。还有SFTP
    //    * SMTP（简单邮件传输协议）：用于发送电子邮件。
    //    * POP（邮局协议）和IMAP（Internet邮件访问协议）：用于接收和管理电子邮件。
    //    * Telnet（远程终端协议）和SSH（安全外壳协议）：用于远程登录和执行命令。

    //说明，有的还需要有超时功能，发送请求超过指定时间无响应，应返回对应信息
    //另外还有重发功能，重新发送请求

    /**
     * 向指定URL发送GET请求
     *
     * @param url   请求URL
     * @param param 请求参数，格式：name1=value1&name2=value2
     * @return 响应结果
     */
    public static String sendGet(String url, String param) throws IOException {
        String urlStr = url + "?" + param;
        URL realUrl = new URL(urlStr);
        URLConnection urlConnection = realUrl.openConnection();
        StringBuilder result = new StringBuilder();
        urlConnection.setRequestProperty(USER_AGENT, USER_AGENT_VALUE);
        urlConnection.setRequestProperty(CONNECTION, CONNECTION_VALUE);
        urlConnection.setRequestProperty(ACCEPT, "*/*");
        urlConnection.connect();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()))) {
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            log.error("请求异常-sendGet：{}", e.getMessage());
        }
        return result.toString();
    }

    public static String sendPost(String url, String param) throws IOException {
        String urlStr = url;
        URL realUrl = new URL(urlStr);
        URLConnection urlConnection = realUrl.openConnection();
        StringBuilder result = new StringBuilder();
        urlConnection.setDoInput(true);
        urlConnection.setDoOutput(true);
        urlConnection.setRequestProperty(CONTENTTYPE, UTF8);
        urlConnection.setRequestProperty(ACCEPT_CHARSET, UTF8);
        urlConnection.setRequestProperty(USER_AGENT, USER_AGENT_VALUE);
        urlConnection.setRequestProperty(CONNECTION, CONNECTION_VALUE);
        urlConnection.setRequestProperty(ACCEPT, "*/*");
        urlConnection.connect();
        try (PrintWriter out = new PrintWriter(urlConnection.getOutputStream()); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), UTF8))) {
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            out.flush();
            out.print(param);
        } catch (Exception e) {
            log.error("请求异常-sendPost：{}", e.getMessage());
        }
        return result.toString();
    }

    public static String sslSendPost(String url, String param) throws IOException {
        String urlStr = url + "?" + param;
        StringBuilder result = new StringBuilder();
        try {
            SSLContext sslInstance = SSLContext.getInstance(SSL);
            sslInstance.init(null,
                    new TrustManager[]{new TrustAnyTrustManager()},
                    new SecureRandom());

            URL realUrl = new URL(urlStr);
            HttpsURLConnection connection = (HttpsURLConnection) realUrl.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestProperty(CONTENTTYPE, UTF8);
            connection.setRequestProperty(ACCEPT_CHARSET, UTF8);
            connection.setRequestProperty(USER_AGENT, USER_AGENT_VALUE);
            connection.setRequestProperty(CONNECTION, CONNECTION_VALUE);
            connection.setRequestProperty(ACCEPT, "*/*");

            connection.setSSLSocketFactory(sslInstance.getSocketFactory());
            connection.setHostnameVerifier(new TrustAnyHostnameVerifier());

            connection.connect();

            InputStream inputStream = connection.getInputStream();
            BufferedReader data = new BufferedReader(new InputStreamReader(inputStream));
            String ret = "";
            while (ret != null) {
                ret = data.readLine();
                if (ret != null && !ret.trim().equals("")) {
                    result.append(ret);
                }
            }
            connection.disconnect();
            data.close();
        } catch (Exception e) {
            log.error("请求异常-sslSendPost：{}", e.getMessage());
        }
        return result.toString();
    }

    private static class TrustAnyTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {

        @Override
        public boolean verify(String s, SSLSession sslSession) {
            return true;
        }
    }
}
